home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
EMSIF230.ARJ
/
EMSIF.DOC
next >
Wrap
Text File
|
1991-12-01
|
53KB
|
1,162 lines
EMSIF
Version-independent C Interface to LIM EMS Functions
for LIM EMS versions 3.0 and higher
EMSIF version 2.3
by James W. Birdsall
12/01/91
0. CONTENTS
-----------
0. CONTENTS
I. INTRODUCTION
I.1 WHAT IS SUPPORTED
I.2 COPYRIGHT, LICENSE, AND WARRANTY DISCLAIMER
II. COMPILING AND LINKING WITH THE LIBRARIES
II.1 WITH C
II.2 WITH C++
II.3 EMSTEST, THE EXAMPLE PROGRAM
III. PROGRAMMING WITH EMSIF
III.1 INITIALIZING THE LIBRARY
III.2 ORDINARY USE
III.3 FRAME CACHING
III.4 SAVE/RESTORE
III.5 OTHER TIPS
III.6 FUNCTION GROUPING
IV. LIBRARY REFERENCE
IV.1 GLOBAL VARIABLES
IV.2 FUNCTIONS
V. ERROR CODES
V.1 INTERNAL ERRORS
V.2 EMS DRIVER ERRORS
VI. THE END
VI.1 ACKNOWLEDGEMENTS
I. INTRODUCTION
---------------
EMSIF provides a high-level interface to LIM EMS control functions
for common operations such as allocating, mapping, and freeing EMS, and
copying data to and from EMS. The interface has been made independent of
the EMS version implemented by the EMS driver as far as possible, so
that parameters and returned data are always in the same format, but the
EMS call most appropriate to the EMS version implemented by the driver
is used.
EMSIF is written in assembly language for speed and assembled with
Borland's Turbo Assembler (TASM) 2.5. The source code is not compatible
with the Microsoft Assembler (MASM).
I.1 WHAT IS SUPPORTED
---------------------
EMSIF expressly supports the Lotus-Intel-Microsoft (LIM) Expanded
Memory Specification (EMS) versions 3.0, 3.2, and 4.0. Versions above
4.0 are supported as 4.0. Versions below 3.0 are not supported.
Save/restore is not supported under version 3.0, and assigning names to
EMS handles is only supported under version 4.0. These exceptions to
version-independence are due to limitations of the unsupported versions;
the necessary services are not available from the driver.
EMSIF supports tiny, small, medium, compact, large, and huge memory
models. The small model library supports both tiny and small models, so
no library is provided specifically for tiny model.
EMSIF supports any version of Turbo C, Turbo C++, or Borland C++, in
both C and C++ modes, and Microsoft C 6.00 and 6.00A. EMSIF has been
tested with Borland C++ 2.0, Turbo C 2.0, and Microsoft C 6.00A in all
of the supported memory models. EMSIF should work with earlier versions
of Microsoft C and any other C compiler that 1) uses compatible
parameter passing and return methods and 2) can use standard-format
libraries.
I.2 COPYRIGHT, LICENSE, AND WARRANTY DISCLAIMER
-----------------------------------------------
EMSIF is not in the public domain. All the files are copyright 1991
by James W. Birdsall, all rights reserved. Permission is granted to do
the following:
You may freely redistribute this archive, so long as it contains
all the files listed in the file MANIFEST, intact and
unmodified.
You may use the libraries in programs for your own use. You may
not distribute programs linked with these libraries.
Payment of the $5 shareware registration fee ($50 for commercial use)
grants the following license, in addition to the permissions listed
above:
You may request the source to EMSIF. You may modify the source
as necessary for use in your programs. However, you may not
redistribute either the original or modified source.
You may distribute programs linked with either the original
libraries or libraries generated from source you have modified,
without royalty, provided you (a) do not alter or remove
copyright notices contained therein and (b) you indemnify, hold
harmless, and defend the author from and against any claims or
lawsuits, including attorney's fees, that arise or result from
the use or distribution of your software product.
For the purposes of this license, commercial use is defined as use by an
incorporated entity in a software product that is regarded as the
product of the corporation, no matter how the software product is
distributed, but only if 100 or more copies of the product are expected
to be made.
The contents of the distribution archive, and all other related
files, information, and services are provided "as is" and without
warranty. To the extent permitted by applicable law, the author
disclaims all warranties, express or implied, including but not limited
to, any implied warranty of merchantability or fitness for a particular
purpose. While effort has been made to ensure that the files, information,
and services are accurate and correct, the author shall not be liable
for damages arising out of the use of or inability to use this product,
including but not limited to, loss of profit, data, or use of this
software, or special, incidental, or consequential damages or other
similar claims, even if the author has been specifically advised of the
possibility of such damages. Some states do not allow the exclusion of
incidental or consequential damages, so the foregoing limitation may not
apply to you.
Information on contacting the author is provided at the end of this
file.
II. COMPILING AND LINKING WITH THE LIBRARIES
--------------------------------------------
This section describes how to use the EMSIF libraries with your
programs.
EMSIF is provided as Borland/Microsoft standard library files.
Libraries are provided for small, medium, compact, large, and huge
memory models (tiny model uses the small model library). The model for
which a library is intended is indicated by the last letter of the
filename proper, which is the same as the first letter for the model.
For example, EMSIFL.LIB is the large model library.
II.1 WITH C
-----------
To use EMSIF in C programs, you must #include the file EMSIF.H in
every source file that calls EMSIF functions, accesses EMSIF global
variables, or uses #defined constants provided by EMSIF.
The procedures for linking EMSIF with the rest of your program vary
according to the compiler and method you are using. In general, you must
include the appropriate library (the library corresponding to the memory
model in which you have compiled the rest of your program) in the link.
If you are compiling in the Integrated Development Environment of
Turbo/Borland C[++], you should include the name of the appropriate
library in the project file for your program. For example, if you are
working in the compact memory model, you should include EMSIFC.LIB in
your project file.
If you are using a command-line compiler (bcc, tcc, or cl) to compile
and link, simply place the full name of the appropriate EMSIF library on
the command line. For example, "bcc -mc foo.c emsifc.lib" will compile
the file "foo.c" in the compact model and link it with emsifc.lib.
If you are linking manually (using TLINK or LINK), place the name of
the appropriate library in with the other libraries. For example,
tlink c0c.obj foo.obj, foo.exe, foo.map, cc.lib emsifc.lib
or
link foo.obj, foo.exe, foo.map, emsifc.lib ;
will link the object "foo.obj" with the appropriate startup object and
standard library (LINK automatically includes the startup object and
standard library, so it is not necessary to explicitly include them) and
the compact model EMSIF library.
II.2 C++
--------
To use EMSIF in C++ programs, you must #include the file EMSIF.HPP in
every file that calls EMSIF functions, accesses EMSIF global variables,
or uses #defined constants provided by EMSIF. Be careful to include
EMSIF.HPP instead of EMSIF.H. If you include the wrong one, you will
probably see "undefined symbol" errors when linking.
Otherwise, the procedures for using EMSIF with C++ programs are the
same as for using it with C programs.
II.3 EMSTEST, THE EXAMPLE PROGRAM
---------------------------------
A large and complete example program and tester, EMSTEST, has been
included in this distribution. It can be compiled in any of the
supported memory models (although tiny model requires some contortions
to do so), with either Borland or Microsoft compilers.
The test program has four source files: EMSTEST.C, EMSTEST2.C,
EMSTEST3.C, and TESTUTIL.C, and two header files: EMSTEST.H and
TESTUTIL.H. When compiling in tiny model with Borland compilers, an
additional source file, STACK.ASM, is needed. STACK.OBJ, which is
STACK.ASM pre-assembled, has been included for those who do not have
assemblers.
Example makefiles have been included for Borland and Microsoft
compilers. EXMAKEBC is the example makefile for Borland C++ 2.0,
EXMAKETC is the example makefile for Turbo C[++], and EXMAKEMS is the
example makefile for Microsoft C. Complete instructions for making the
example program and using the example makefiles are included at the
beginning of each makefile. More information about the program is also
included at the beginning of EMSTEST.C.
EMSTEST requires at least eight pages of available expanded memory
and at least 190,000 bytes of available conventional memory to run.
III. PROGRAMMING WITH EMSIF
----------------------------
This section describes how to make EMSIF calls in your program, and
details various tricks and tips which you may find useful.
III.1 INITIALIZATION
--------------------
The library initialization function EMMlibinit() _must_ be called
before any other EMSIF calls are made. All other EMSIF functions are
guaranteed to fail if called before EMMlibinit(). EMMlibinit()
determines whether an EMS driver is present and sets up various internal
and global variables necessary to the functioning of EMSIF.
III.2 ORDINARY USE
------------------
EMSIF provides several sets of functions. First, there is a set of
functions which are intended to be orthogonal with the standard C
functions malloc() and free(), and the Borland/Turbo C[++] function
coreleft(). These functions are EMMalloc(), EMMfree(), and
EMMcoreleft().
Second, there is a group of functions for copying data to and from
expanded memory. These functions allow you to treat allocated blocks of
expanded memory pages as linear memory, hiding the details of page
mapping. These functions are EMMcopyto(), EMMcopyfrom(), EMMicopyto(),
EMMicopyfrom(), _EMMicopyto(), and _EMMicopyfrom().
Third, there is a group of low-level functions which allow more
direct access to EMS driver calls. These functions are EMMallocpages(),
EMMgetframeaddr(), EMMgetnumframe(), EMMgetsinfraddr(), and
EMMmappage(). With these functions it is possible to duplicate the
copying functions or access expanded memory in other ways. Calls to
these functions can be mixed with calls to copying functions without
trouble.
Fourth, there is a group of miscellaneous functions: EMMgetname(),
EMMsetname(), EMMgetversion(), EMMsave(), and EMMrestore().
Finally, there is a group of functions which affect only the
operation of EMSIF itself: _EMMenc(), _EMMdisc(), _EMMinval(),
EMMlibinit(), and EMMsrinit(). For details on all the functions listed
above, see section IV.2.
To use expanded memory, first it is necessary to allocate some. This
can be done with either EMMalloc(), which takes a size in bytes, or
EMMallocpages(), which allocates EMS pages directly. Both return a
handle which will be used to reference the allocated memory.
To access the expanded memory, you can either use the copying
functions, or access it directly. The copying functions are pretty
self-explanatory. Accessing expanded memory directly is more
complicated. First, it is necessary to determine the addresses of the
EMS page frames. EMS page frames 0 through 3 are available under all EMS
versions and are intended for general use. While EMS version 4.0
provides additional page frames, they are intended for use by
multitaskers such as Quarterdeck DesqView and Microsoft Windows. These
additional page frames may appear anywhere, even in the middle of your
program. Use them only with great caution. To obtain the addresses of
all page frames, use EMMgetframeaddr(). To obtain the address of a
single page frame, use EMMgetsinfraddr(). The addresses returned by both
these functions are segment addresses and must be converted to far
pointers before actually being used.
Having decided which page frame or frames you wish to use, and
determined the necessary addresses, it is then necessary to map EMS
logical pages into the page frame(s). This is accomplished with
EMMmappage(). Once this is done, you can then access any byte in that
logical page (which is 16384 bytes long) using the far pointer created
earlier. Mapping a logical page into a page frame into which a
logical page has already been mapped causes the original logical page to
be displaced by the new logical page. A logical page may be mapped in
any number of times (although having one mapped into multiple page
frames simultaneously may cause unexpected results), and a page frame
can have logical pages mapped into it any number of times (but only the
last one mapped into a given page frame is accessible in that page
frame).
The miscellaneous functions listed above allow you to determine the
EMS version supported by the driver (EMMgetversion()), to associate a
string name with an EMS handle and retrieve the name associated with an
EMS handle (EMMsetname()/EMMgetname()), and save and restore EMS page
mappings (EMMsave()/EMMrestore()). More information on the last is
available in section III.4.
The internal functions _EMMenc(), _EMMdisc(), and _EMMinval() are
discussed in section III.3 below. EMMlibinit() has already been
discussed, in section III.1, and EMMsrinit() is discussed in section
III.4 below.
Many functions return a status directly. For those functions, a
return value of 0 indicates success and a return value of EMMOOPS
indicates failure. The global variable _EMMerror contains an error code
which gives further information on why the function failed, or has value
0 if the function succeeded. Many functions return some other value
instead of a status code (0 or EMMOOPS). In these cases, the value of
_EMMerror should be checked upon return. The recommended method of
error-checking is indicated for each function in section IV.2 below.
III.3 FRAME CACHING
-------------------
EMSIF uses a technique called "frame caching" to speed up the copying
functions. It keeps track of the handle and page number of the logical
page currently mapped into page frame 2. When starting a copy, EMSIF
calculates the handle and logical page needed, and if that page is
already mapped into page frame 2, does not perform a mapping call. This
technique can greatly increase the copying speed, especially if many
separate copies to the same page are being performed.
Frame caching is on by default. To check the current setting, inspect
the global variable _EMMframecache. If it is nonzero, frame caching is
on; if it is 0, frame caching is off. The state of frame caching is
changed via the functions _EMMenc() (enable caching) and _EMMdisc()
(disable caching).
Frame caching has one unfortunate weakness. It assumes that all EMS
mapping activity will be performed via EMSIF, so that an accurate record
of the contents of frame 2 can be kept. If you are using another
third-party library that also uses EMS, then obviously there is mapping
activity that is not performed via EMSIF, and frame caching will cause
the copying functions to malfunction.
This is why _EMMenc() and _EMMdisc() were created. If you have this
problem, you have a number of options:
1) You can disable frame caching globally. Just call _EMMdisc()
somewhere between the EMMlibinit() call and the first call to
an EMSIF copying function. If you mostly do large copies,
especially copies which cross page boundaries, then there
will be almost no performance loss. If you do lots of
separate copies to the same page, performance may drop by up
to 50% or more. In that case, you should probably pick
another option.
2) You can disable frame caching around calls to the other
library. If the calls to the other library occur in clusters,
you can call _EMMdisc() before the cluster and _EMMenc()
after. Alternatively, if the calls to EMSIF form more
convenient clusters, you can call _EMMenc() before and
_EMMdisc() after. Note that _EMMdisc() sets a flag which
invalidates the current cache contents, so that when caching
is re-enabled EMSIF does not become confused.
3) If calls to the other library are sparse, you can simply
invalidate the cache each time you make a call to the other
library, using the macro _EMMinval(). It does not matter
whether you call _EMMinval() before or after the call to the
other library, as long as the cache is invalidated before the
next EMSIF copying call is made.
III.4 SAVE/RESTORE
------------------
Worse interactions with other libraries can occur. If the other
library assumes that the EMS mapping will not change between calls to
it, then almost any EMSIF activity at all will interfere with the other
library. This is why save/restore capability was added to EMSIF. Note
that save/restore only works with EMS version 3.2 and up. While EMS
version 3.0 claimed to have save/restore capability, it is so radically
different from that in versions 3.2 and up that it cannot be
consolidated under the same interface. If you use save/restore in your
program, you give up compatibility with EMS version 3.0.
The EMS specification (for versions 3.2 and up) includes calls to
save the current EMS mapping to a buffer in memory, and restore a
mapping from such a buffer. EMSIF's save/restore function are an
interface to these calls. Before any save/restore calls can be made,
EMMsrinit() must be called to initialize save/restore. It takes a single
parameter, which is a pointer to a function used to allocate save
buffers. Malloc() may be passed in any memory model, but any other
function with the same prototype may be used. Note that the passed
function will never be required to allocate more that 255 bytes in one
call.
Having initialized save/restore, you can call EMMsave() to save a
mapping and EMMrestore() to restore one. The pointer returned by
EMMsave() is the value returned by an internal call to the function
which was passed to EMMsrinit(), and may be freed when necessary with
whatever function would ordinarily be called; for example, if malloc()
was passed to EMMsrinit(), then pointers returned by EMMsave() may be
passed to free(). Note that EMMrestore() does not free save buffers. You
must free them yourself.
To avoid interference with libraries that assume that the EMS mapping
will not change, simply call EMMsave() after calls to that library, and
call EMMrestore() with the pointer returned by the last EMMsave() before
the next call to that library. Note that EMMrestore() invalidates the
frame cache. In fact, if you have to use save/restore in this way, it
would probably be best to disable frame caching globally, perhaps
enabling it around loops which perform lots of copies if you really need
the performance boost.
Save/restore can also be used to quickly alternate between several
complex mappings. Having established a mapping, save it with EMMsave().
Then, when you need it again, a call to EMMrestore() will restore it
quickly and easily. A given mapping may be restored from the same buffer
any number of times.
III.5 OTHER TIPS
----------------
Expanded memory is not deallocated automatically when a program
exits. If the program does not deallocate expanded memory it has
allocated, that expanded memory is stuck, not available to any other
program until the machine is rebooted. Under normal circumstances, it is
easy enough to free expanded memory when it is no longer needed.
However, an emergency exit due to the user hitting control-break or due
to a hardware error (e.g. the famous "Abort, Retry, Fail?") can cause
expanded memory to become stuck unless your program takes special
measures to intercept these errors and perform cleanup before exiting.
There are a number of ways to do this and they vary from compiler to
compiler. Look for functions named things like ctrlbrk(), harderr() and
signal().
If you are copying array elements, _EMMicopyto()/_EMMicopyfrom() or
EMMicopyto()/EMMicopyfrom() may be more efficient. These functions allow
copying of elements of fixed size which are separated by gaps also of
fixed size. For example, if you have an array of integers and wish to
copy all the even-indexed elements (a[0], a[2], a[4], etc.), these
functions are far faster than calling a standard copying function
(EMMcopyto() or EMMcopyfrom()) from within a loop. While the performance
improvement varies from machine to machine, the smallest speed increase
that I have seen is seven times, ranging up to over twenty times on a
fast machine with frame caching off.
III.6 FUNCTION GROUPING
-----------------------
The EMSIF functions have been arranged in the library in such a way
as to reduce the number of unnecessary functions linked into your
program. There are currently five groups:
FUNCTIONS VARIABLES
--------- ---------
GROUP 1: EMMlibinit(), EMMgetversion(), _EMMerror, _EMMversion,
EMMgetnumframe(), EMMgetsinfraddr(), _EMMframecache,
EMMgetframeaddr(), EMMmappage() emsif_vers_vers,
emsif_vers_date,
emsif_vers_time
GROUP 2: EMMcoreleft(), EMMallocpages(), none
EMMalloc(), EMMfree()
GROUP 3: EMMcopyto(), EMMcopyfrom(), none
_EMMicopyto(), _EMMicopyfrom(),
_EMMenc(), _EMMdisc()
GROUP 4: EMMsrinit(), EMMsave(), EMMrestore() none
GROUP 5: EMMgetname(), EMMsetname() none
If your program references any of the functions or variables in a group,
all the functions and variables in that group will be linked in. Note
that group one will always be linked, since it contains EMMlibinit(),
which all EMSIF-using programs must call.
IV. LIBRARY REFERENCE
---------------------
IV.1 GLOBAL VARIABLES
---------------------
_EMMerror
---------
unsigned char const _EMMerror;
_EMMerror contains the error code from the last EMSIF call. If the
call succeeded, _EMMerror will be 0. If the call failed because the EMS
driver returned an error, _EMMerror contains the error code returned by
the EMS driver. If the call failed because EMSIF detected an error
internally, _EMMerror contains an intenal error code. A list of error
code values, their meanings, and #defined constants for them is in
section V.
_EMMframecache
--------------
unsigned char const _EMMframecache;
_EMMframecache is a flag which indicates whether frame caching is
enabled or not. A nonzero value indicates that frame caching is enabled,
and 0 indicates that frame caching is disabled. See section IV.3 for a
discussion of frame caching.
_EMMversion
-----------
unsigned char const _EMMversion;
_EMMversion contains the EMS version implemented by the EMS driver in
packed BCD format. For example, if the EMS version is 4.0, the value of
_EMMversion will be 0x40. If _EMMversion is 0x32, the EMS version is
3.2. This value is the same as that returned by EMMgetversion().
emsif_vers_vers, emsif_vers_date, emsif_vers_time
-------------------------------------------------
char const emsif_vers_vers[];
char const emsif_vers_date[];
char const emsif_vers_time[];
These are null-terminated strings containing information about the
name and version of the library, the date of assembly, and the time of
assembly, respectively.
IV.2 FUNCTIONS
--------------
_EMMdisc() - disable frame caching
----------
void _EMMdisc(void);
void _EMMenc(void);
void _EMMinval(void);
_EMMdisc() disables frame caching, invalidates the current cache
contents, and sets _EMMframecache to zero. _EMMerror should be checked
after calling this function. It is not an error to call this function
when frame caching is already disabled.
_EMMenc() enables frame caching, invalidates the current cache
contents, and sets _EMMframecache to a nonzero value. _EMMerror should
be checked after calling this function. It is not an error to call this
function when frame caching is already enabled; however, the current
cache contents will still be invalidated.
_EMMinval() is a macro that invalidates the current cache contents if
frame caching is enabled, or has no effect if frame caching is disabled.
The frame caching status is not changed. _EMMerror should be checked
afterwards.
For more information on frame caching, see section III.3.
_EMMenc() - enable frame caching
---------
void _EMMenc(void);
See _EMMdisc();
_EMMicopyfrom() - copy data by intervals from EMS
---------------
int _EMMicopyfrom(unsigned long nelem, int elsize,
unsigned int srcskip, int handle, unsigned long foffset,
unsigned char far *dest, unsigned int destskip);
int _EMMicopyto(unsigned long nelem, int elsize,
unsigned int srcskip, unsigned char far *source,
int handle, unsigned long foffset, unsigned int destskip);
_EMMicopyfrom() allows painless copying of array elements from
expanded memory to conventional memory. EMS mapping, calculation of
addresses, skipping of unwanted elements, etc., are all handled by the
function. Elements spread across more than 64K, or totalling more than
64K in length, can be copied without special treatment.
Nelem elements are copied, each of which is elsize bytes long. The
elements are copied from the EMS pages owned by handle, starting at byte
offset foffset and with srcskip bytes between elements, to conventional
memory starting at dest with destskip bytes between elements. Dest must
be a far pointer; a near pointer can be converted to a far pointer with
a cast when the function is called. Byte offsets in EMS are as for
EMMcopyfrom().
If nelem or elsize is zero, the function returns immediately without
error. Elsize must be in the range 0 through 16384, or the function will
return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
range 0 through 32768, or the function will return with error
EMM_SKTOOBIG.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
_EMMicopyto() allows painless copying of array elements from
conventional memory to expanded memory. EMS mapping, calculation of
addresses, skipping of unwanted elements, etc., are all handled by the
function. Elements spread across more than 64K, or totalling more than
64K in length, can be copied without special treatment.
Nelem elements are copied, each of which is elsize bytes long. The
elements are copied from conventional memory starting at source with
srcskip bytes between elements, to the EMS pages owned by handle, starting
at byte offset foffset and with destskip bytes between elements. Source
must be a far pointer; a near pointer can be converted to a far pointer
with a cast when the function is called. Byte offsets in EMS are as for
EMMcopyto().
If nelem or elsize is zero, the function returns immediately without
error. Elsize must be in the range 0 through 16384, or the function will
return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
range 0 through 32768, or the function will return with error
EMM_SKTOOBIG.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
_EMMicopyto() - copy data by intervals to EMS
-------------
int _EMMicopyto(unsigned long nelem, int elsize,
unsigned int srcskip, unsigned char far *source,
int handle, unsigned long foffset, unsigned int destskip);
See _EMMicopyfrom().
_EMMinval() - invalidate frame cache contents
-----------
void _EMMinval(void);
See _EMMdisc().
EMMalloc() - allocate EMS
----------
int EMMalloc(unsigned long bytes);
int EMMallocpages(int pages);
EMMalloc() allocates EMS memory. It takes the given number of bytes
and allocates the smallest number of pages which contain that many
bytes. It returns the EMS handle assigned by the EMS driver. _EMMerror
should be checked after calling this function.
Note that EMS cannot be allocated in units smaller than a page (16384
bytes). Requesting one byte will allocate a whole page; 16385 bytes will
allocate two pages. Requesting zero bytes allocates one page.
EMMallocpages() allocates EMS memory by pages directly. It returns
the EMS handle assigned by the EMS driver. _EMMerror should be checked
after calling this function. It is possible to allocate 0 pages with
this function, but only under EMS version 4.0; under earlier versions,
allocating 0 pages is an error.
EMMallocpages() - allocate EMS by pages
---------------
int EMMallocpages(int pages);
See EMMalloc().
EMMcopyfrom() - copy data from EMS
-------------
int EMMcopyfrom(unsigned long copylen,
int handle, unsigned long foffset,
unsigned char far *dest);
int EMMcopyto(unsigned long copylen,
unsigned char far *source,
int handle, unsigned long foffset);
EMMcopyfrom() allows painless copying of blocks of data from expanded
memory to conventional memory. All mapping, calculation of addresses,
etc., is handled by the function. Copies longer than 64K are possible
without special treatment.
Copylen bytes of data are copied, from the EMS pages owned by handle,
starting at byte offset foffset, to the conventional memory area pointed
to by dest. Dest must be a far pointer; a near pointer can be converted
to a far pointer with a cast when the function is called. To convert an
expanded memory offset (such as foffset) to a page and offset within
that page, divide the offset by the size of a page (16384 bytes). The
quotient is the page number and the remainder is the offset within that
page. Offsets 0 through 16383 are in page 0; offsets 16384 through 32767
are in page 1, etc. This feature allows you to treat expanded memory
blocks as linear memory rather than a collection of pages.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror. If copylen is 0, the function
returns immediately without error.
EMMcopyto() is the mirror image of EMMcopyfrom(). It allows painless
copying of blocks of data from conventional memory to expanded memory.
All mapping, calculation of addresses, etc., is handled by the function.
Copies longer than 64K are possible without special treatment.
Copylen bytes of data are copied, from the conventional memory area
pointed to by source, to the EMS pages owned by handle, starting at
byte offset foffset. Expanded memory offsets are as in EMMcopyfrom().
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror. If copylen is 0, the function
returns immediately without error.
See also EMMicopyto() and EMMicopyfrom().
EMMcopyto() - copy data to EMS
-----------
int EMMcopyto(unsigned long copylen,
unsigned char far *source,
int handle, unsigned long foffset);
See EMMcopyfrom().
EMMcoreleft() - get amount of free EMS
-------------
unsigned long EMMcoreleft(void);
This function returns the amount of EMS memory available, in bytes.
To determine the number of EMS pages available, divide the returned
value by 16384. _EMMerror should be checked after calling this function.
EMMfree() - deallocate EMS
---------
int EMMfree(int handle);
This function accepts an EMS handle (as returned by EMMalloc() or
EMMallocpages(), or otherwise obtained from the EMS driver) and releases
it and any EMS pages allocated to it. This function returns 0 on success
or EMMOOPS on error. The specific error may be determined from
_EMMerror.
EMMgetframeaddr() - get EMS page frame segment addresses
-----------------
int EMMgetframeaddr(frameinfo *buffer);
int EMMgetnumframe(void);
unsigned int EMMgetsinfraddr(int frame);
EMMgetframeaddr() returns the segment addresses of all the EMS page
frames. Buffer is a pointer to an array of frameinfo structures; this
array is assumed to be large enough to contain information about all the
frames. The number of frameinfo structures needed can be determined with
the EMMgetnumframe() function described below.
Each frameinfo structure contains the number and the segment address
of a frame. Check EMSIF.H or EMSIF.HPP for the exact format of the
frameinfo structure. The information is returned in whatever order the
EMS driver provides it, which is typically sorted by address rather than
frame number. Do NOT just assume that the first element in the array
contains information for frame 0! The segment addresses returned must be
converted to far pointers (using MK_FP() or your compiler's equivalent)
before they can be used to access memory.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
EMMgetnumframe() returns the number of EMS page frames present in the
system. For EMS versions below 4.0, this will always be 4. For EMS
version 4.0, it will be at least 4. _EMMerror should be checked after
calling this function.
EMMgetsinfraddr() returns the segment address of a particular EMS
page frame. This address must be converted to a far pointer (using
MK_FP() or your compiler's eqivalent) before it can be used to access
memory.
Note that this function calls EMMgetframeaddr() internally and
allocates a temporary buffer for it on the stack. Therefore, depending
on how many page frames the system has, this function may require many
bytes of stack space.
_EMMerror should be checked after calling this function.
EMMgetname() - obtain string name associated with an EMS handle
------------
int EMMgetname(int handle, char *name);
int EMMsetname(int handle, char *name);
EMMgetname() returns (as a null-terminated string) the name, if any,
assigned to an EMS handle. Real names are only implemented in EMS
version 4.0. Under earlier versions, this function fills the name buffer
with nulls ('\0'), which is also the return under version 4.0 when no
name has been associated with the given handle. The buffer pointed to by
name must be at least nine characters long (since an EMS name may be up
to eight characters long and there must be room for a terminating null).
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
EMMsetname() allows the association of a name up to eight characters
long with an EMS handle. It only works for EMS version 4.0; under
earlier versions, it returns the error EMM_BADVERS. Version independence
has been abandoned in this case because the main purpose of associating
a name with an EMS handle is to allow several different programs to
recognize shared data. While EMSIF could implement a naming function
within itself, the names would not be visible outside the program
assigning the name, defeating the purpose of doing so in the first
place. This function returns 0 on success or EMMOOPS on error. The
specific error may be determined from _EMMerror.
EMMgetnumframe() - obtain number of EMS page frames
----------------
int EMMgetnumframe(void);
See EMMgetframeaddr().
EMMgetsinfraddr() - get segment address of one EMS page frame
-----------------
unsigned int EMMgetsinfraddr(int frame);
See EMMgetframeaddr().
EMMgetversion() - obtain EMS version implemented by EMS driver
---------------
int EMMgetversion(void);
This function returns the EMS version implemented by the EMS driver.
The version number is in packed BCD format as in the global variable
_EMMversion, and is in fact the same value. _EMMerror should be checked
after calling this function.
EMMicopyfrom() - copy data by intervals from EMS
--------------
int EMMicopyfrom(unsigned long nelem, int elsize, unsigned int byteskip,
int handle, unsigned long foffset,
unsigned char far *dest);
int EMMicopyto(unsigned long nelem, int elsize, unsigned int byteskip,
unsigned char far *source,
int handle, unsigned long foffset);
EMMicopyfrom() is a macro which calls _EMMicopyfrom(). It allows
painless copying of array elements from expanded memory to conventional
memory. EMS mapping, calculation of addresses, skipping of unwanted
elements, etc., are all handled by the function. Elements spread across
more than 64K, or totalling more than 64K in length, can be copied without
special treatment.
Nelem elements are copied, each of which is elsize bytes long, with
byteskip bytes between elements at both source and destination. The
elements are copied from the EMS pages owned by handle, starting at byte
offset foffset, to conventional memory starting at dest. Dest must be a
far pointer; a near pointer can be converted to a far pointer with a cast
when the function is called. Byte offsets in EMS are as for EMMcopyfrom().
If nelem or elsize is zero, the function returns immediately without
error. Elsize must be in the range 0 through 16384, or the function will
return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
range 0 through 32768, or the function will return with error
EMM_SKTOOBIG.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
EMMicopyto() is a macro which calls _EMMicopyto(). It allows painless
copying of array elements from conventional memory to expanded memory.
EMS mapping, calculation of addresses, skipping of unwanted elements,
etc., are all handled by the function. Elements spread across more than
64K, or totalling more than 64K in length, can be copied without special
treatment.
Nelem elements are copied, each of which is elsize bytes long, with
byteskip bytes between elements at both source and destination. The elements
are copied from conventional memory starting at source, to the EMS pages
owned by handle, starting at byte offset foffset. Source must be a far
pointer; a near pointer can be converted to a far pointer with a cast when
the function is called. Byte offsets in EMS are as for EMMcopyto().
If nelem or elsize is zero, the function returns immediately without
error. Elsize must be in the range 0 through 16384, or the function will
return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
range 0 through 32768, or the function will return with error
EMM_SKTOOBIG.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
EMMicopyto() - copy data by intervals to EMS
------------
int EMMicopyto(unsigned long nelem, int elsize, unsigned int byteskip,
unsigned char far *source,
int handle, unsigned long foffset);
See EMMicopyfrom().
EMMlibinit() - initialize EMSIF
------------
int EMMlibinit(void);
EMMlibinit() initializes EMSIF. Any other EMSIF function will return
with error EMM_NOINIT (in _EMMerror) if called before EMMlibinit() has
been called. This function returns 0 on success, EMMOOPS on error, or
NOEMM if no EMS driver is detected. The specific error may be determined
from _EMMerror. Note that EMSIF will not initialize if the EMS driver
claims that fewer than four EMS page frames exist, since that is a
violation of the EMS specification and the driver may have other
anomalies that EMSIF does not know how to handle.
Detection of the EMS driver relies on DOS services, so this library
cannot be used in a device driver as it stands. If you need this library
for a device driver or other program that cannot access DOS services,
you can buy the source (it's cheap) and easily modify EMMlibinit() to
use another method of detection. There are no other calls to DOS
services in EMSIF. The method used was chosen for its reliability;
there is another method, suitable for use in device drivers, which is
not as reliable and typically is useful _only_ for device drivers.
EMMmappage() - map an EMS logical page into an EMS page frame
------------
int EMMmappage(int frameno, int handle, int logpage);
This function maps a logical page into an EMS page frame so that it
can be accessed. The logical page logpage belonging to handle is mapped
into page frame number frameno. This function returns 0 on success or
EMMOOPS on error. The specific error may be determined from _EMMerror.
EMMrestore() - restore an EMS mapping from a save buffer
------------
int EMMrestore(void *saveblock);
void *EMMsave(void);
int EMMsrinit(void *(*mallocfunc)(size_t));
EMMrestore() restores an EMS mapping that has earlier been saved in a
save buffer with a call to EMMsave(). The contents of the frame cache
are invalidated, since the format of the contents of the save buffer
varies from one EMS driver to the next and it is thus not possible to
determine what will be mapped into the cached frame when the restore is
done. EMMrestore() does not deallocate the save buffer.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror. It is an error if this function
is called before EMMsrinit() has been called.
EMMsave() allocates a save buffer (see EMMsrinit(), below) and saves
the current EMS mapping into it. The current EMS mapping is not changed,
nor are the contents of the frame cache invalidated. This function
returns the pointer returned by the allocation function (see below).
_EMMerror should be checked after calling this function. It is an
error if this function is called before EMMsrinit() has been called.
EMMsrinit() initializes the save/restore capability of EMSIF. It
takes a pointer to a memory-allocation function which is used by
EMMsave() to allocate save buffers. Malloc() is compatible in all memory
models, but any function which works the same way (returns a void
pointer of the size normal for the memory model (near or far), takes a
single parameter of type size_t which is the number of bytes to
allocate, and returns NULL (0) if the memory cannot be allocated) can
also be used. Note that the function will never be required to allocate
more than 255 bytes in one call
EMMsrinit() will fail to initialize and return EMM_BADVERS if the EMS
version is 3.0. Since it did not initialize, EMMsave() and EMMrestore()
will not work either.
_EMMerror should be checked after calling this function.
For more information on frame caching and suggestions on using
save/restore, see sections III.3 and III.4 respectively.
EMMsave() - save an EMS mapping into a save buffer
---------
void *EMMsave(void);
See EMMrestore().
EMMsetname() - associate string name with an EMS handle
------------
int EMMsetname(int handle, char *name);
See EMMgetname().
EMMsrinit() - initialize save/restore
-----------
int EMMsrinit(void *(*mallocfunc)(size_t));
See EMMrestore().
V. ERROR CODES
--------------
This section is a list of the error codes to which the global variable
_EMMerror may be set, and the values and meanings thereof.
V.1 INTERNAL ERRORS
-------------------
Internal codes indicate an error detected by EMSIF itself.
NAME VALUE MEANING
---- ----- -------
EMM_BADVERS 0x40 Bad EMS version, earlier than 3.0.
EMM_BADOFFSET 0x41 Offset plus copy length runs off last
EMS page owned by handle.
EMM_NOFRAME 0x42 Could not find segment address of page frame
used for copying functions (frame 2).
EMM_NOINIT 0x43 EMMlibinit() must be called before any
other EMSIF function can be called.
EMM_FEWFRAMES 0x44 The EMS driver claims that there are fewer
than four page frames.
EMM_NOSR 0x45 EMMsrinit() must be called before
EMMsave() or EMMrestore() can be called.
EMM_MEMNULL 0x46 The save/restore memory allocation
function (the one passed to EMMsrinit())
returned NULL.
EMM_ELTOOBIG 0x47 The element size passed to EMMicopyto()
or EMMicopyfrom() is too big.
EMM_SKTOOBIG 0x48 The skip size passed to EMMicopyto()
or EMMicopyfrom() is too big.
V.2 EMS DRIVER ERRORS
---------------------
These codes are defined in the EMS specification and are returned by
the EMS driver. They are saved in _EMMerror by EMSIF without alteration.
NAME VALUE MEANING
---- ----- -------
EMM_SOFTERROR 0x80 Internal error exists in EMS driver (can
indicate corrupted memory image of driver)
EMM_HARDERROR 0x81 Malfunction in expanded memory hardware
EMM_BUSY 0x82 EMS driver is busy
EMM_BADHANDLE 0x83 Invalid EMS handle
EMM_UNIMP 0x84 Function not defined
EMM_NOFREEHAN 0x85 No free EMS handles
EMM_CONTEXTERR 0x86 Error in save or restore of mapping context
EMM_WAYTOOBIG 0x87 Tried to allocate more pages than physically
exist in system; no pages allocated
EMM_TOOBIG 0x88 Tried to allocate more pages than currently
available; no pages allocated
EMM_TOOSMALL 0x89 Cannot allocate 0 pages
EMM_BADLOGPAGE 0x8A Requested logical page is outside range of
pages owned by handle
EMM_BADFRAMENO 0x8B Illegal frame number in mapping request
EMM_HSTATESAVFULL 0x8C Page-mapping hardware-state save area full
EMM_MSTATESAVFULL 0x8D Mapping-context save failed; save area
already contains context associated with
specified handle
EMM_MSTATERESTERR 0x8E Mapping-context restore failed; save area
does not contain context for specified
handle
EMM_UNIMPSUB 0x8F Subfunction parameter not defined
EMM_BADATTRIB 0x90 Attribute type not defined
EMM_NOFEATURE 0x91 Feature not supported
EMM_SRCOVERWRITE 0x92 Source and destination memory regions have
same handle and overlap; requested move
was performed, but part of the source region
was overwritten
EMM_BADLENGTH 0x93 Copy length longer than actual length
EMM_CONEMSOVERLAP 0x94 Conventional memory region and expanded
memory region overlap
EMM_OFFPAGE 0x95 Specified offset outside logical page
EMM_TOOLONG 0x96 Copy length exceeds one megabyte
EMM_EMSEMSOVERLAP 0x97 Source and destination memory regions have
same handle and overlap; exchange cannot be
performed
EMM_LOST 0x98 Memory source and destination types
undefined
EMM_UNUSED 0x99 This error code is currently unused
EMM_BADALTREG 0x9A Alternate map or DMA register sets are
supported, but specified alternate register
set is not supported
EMM_NOFREEALTREG 0x9B Alternate map or DMA register sets are
supported, but all alternate register sets
are currently allocated
EMM_NOALTREG 0x9C Alternate map or DMA register sets are not
supported, specified alternate register
set is not 0
EMM_BADALTREG2 0x9D Alternate map or DMA register sets are
supported, but the alternate register set
specified is not defined or not allocated
EMM_NODEDDMA 0x9E Dedicated DMA channels are not supported
EMM_BADDEDDMA 0x9F Dedicated DMA channels are supported, but
specified DMA channel is not supported
EMM_UNKNAME 0xA0 Handle for specified name not found
EMM_NAMETAKEN 0xA1 Handle with same name already exists
EMM_ADDRWRAP 0xA2 Memory address wraps; sum of source or
destination region base address and length
exceeds one megabyte
EMM_BADPTR 0xA3 Invalid pointer passed to function, or
contents of source array corrupted
EMM_FORBIDDENFUNC 0xA4 Access to function denied by operating
system
VI. THE END
-----------
Technical support via email is available from the following addresses:
INTERNET:
First choice (the following are alternate addresses for the same place):
support@picarefy.com
picarefy!support@amc.com
picarefy!support@netcom.com
picarefy!support@halcyon.com
amc-gw!picarefy!support@coco.ms.washington.edu
halcyon!picarefy!support@sumax.seattleu.edu
uunet!uw-coco!amc-gw!picarefy!support
Second choice:
jwbirdsa@amc.com
COMPUSERVE:
71261,1731
AMERICA ON-LINE:
GreenTiger
GENIE:
J.BIRDSALL2
Registrations should be sent to:
James W. Birdsall
11112 NE 124 LN #D204
Kirkland, WA 98034
If you have an email address on any of the networks listed above,
please include it when registering, especially if you are requesting
source code. It is much easier to send the source code by email. Also,
please specify what sort of archive (ZIP, ZOO, ARC, LZH, ARJ, UNIX shar)
you can handle most easily.
VI.1 ACKNOWLEDGEMENTS
---------------------
Thanks to Bob Parsons of Parsons Technology Inc. for some good suggestions
on the documentation and for providing the original C++ header file.